package com.example.juc.kingdom_adventures.term9;

import org.junit.Test;

import java.util.concurrent.locks.StampedLock;

public class Client {
    private int number = 0;
    private final StampedLock lock = new StampedLock();

    private void read() {
        // 尝试乐观读取，tryOptimisticRead没有加锁，无须释放
        long stamp = lock.tryOptimisticRead();
        int readNumber = number;
        System.out.println("乐观读取到的 number = " + readNumber);
        // 判断版本号是否被修改过，根据判断结果可知乐观读的结果是否可用
        // 检查乐观读取到的数据是否有误
        // 如果客观读取有误，重新使用读写锁来读数据（重试）
        if (!lock.validate(stamp)) {
            // 读写有误转读写锁，读写互斥
            // 加读锁
            stamp = lock.readLock();
            System.out.println("乐观读取到的 number " + readNumber + " 有误，换用悲观锁重新读取：number = " + number);
            // 释放读锁
            lock.unlockRead(stamp);
        }
    }

    private void write(int change) {
        long stamp = lock.writeLock();
        number += change;
        System.out.println("写入 " + number);
        lock.unlockWrite(stamp);
    }

    @Test
    public void test() throws InterruptedException {
        // 开启一个线程写入 100 次 number
        new Thread(() -> {
            for (int i = 0; i < 100; i++) {
                write(1);
            }
        }).start();

        // 开启一个线程读取 100 次 number
        new Thread(() -> {
            for (int i = 0; i < 100; i++) {
                read();
            }
        }).start();

        // 睡眠一秒保证线程执行完成
        Thread.sleep(1000);
    }
}

